import { BadRequestException, Injectable } from "@nestjs/common";
import { InjectRepository } from "@nestjs/typeorm";
import { Role } from "@/modules/role/entities/role.entity";
import { In, Not, Repository } from "typeorm";
import { Permission } from "@/modules/permission/entities/permission.entity";
import { User } from "@/modules/user/entities/user.entity";
import { SharedService } from "@/shared/shared.service";
import { UserService } from "@/modules/user/user.service";
import { RedisService } from "@/shared/redis.service";
import { PermissionService } from "@/modules/permission/permission.service";
import { AssignRoleToUserDto, GetRoleDto, RoleDto, UpdateRoleDto } from "@/modules/role/dto/dto";
import { CustomException, ErrorCode } from "@/common/exceptions/custom.exception";

@Injectable()
export class RoleService {
  constructor(
    @InjectRepository(Role)
    private readonly roleRepository: Repository<Role>,
    @InjectRepository(Permission)
    private permissionRep: Repository<Permission>,
    @InjectRepository(User)
    private userRepository: Repository<User>,
    private sharedService: SharedService,
    private userService: UserService,
    private redisService: RedisService,
    private permissionService: PermissionService,
  ) {}

  // 创建角色
  async createRole(createRoleDto: RoleDto) {
    // 检查当前角色是否存在
    const existRole = await this.roleRepository.findOne({
      where: [{ roleName: createRoleDto.roleName }, { roleCode: createRoleDto.roleCode }],
    });
    if (existRole) throw new BadRequestException('角色已存在（角色名和角色编码不能重复）');
    const role = this.roleRepository.create(createRoleDto);
    if (createRoleDto.permissionIds) {
      role.permissions = await this.permissionRep.find({
        where: { id: In(createRoleDto.permissionIds) },
      });
    }
    return this.roleRepository.save(role);
  }

  // 删除角色
  async removeRole(roleID: number) {
    const role = await this.roleRepository.findOne({
      where: { id: roleID },
      relations: { users: true },
    });
    if (!role) throw new BadRequestException('角色不存在或者已删除');
    if (role.users?.length) throw new BadRequestException('当前角色存在已授权的用户，不允许删除！');
    await this.roleRepository.remove(role);
    return true;
  }

  // 更新角色的信息以及权限
  async updateRole(number: number, updateRoleDto: UpdateRoleDto) {
    const { roleName, roleCode } = updateRoleDto;
    if (roleName || roleCode) {
      const existRole = await this.roleRepository.findOne({
        where: [
          { roleName, id: Not(number) },
          { roleCode, id: Not(number) },
        ],
      });
      if (existRole) throw new BadRequestException('角色名或者角色编码已存在');
    }
    const role = await this.roleRepository.findOne({ where: { id: number } });
    if (!role) throw new BadRequestException('角色不存在或者已删除');
    const newRole = this.roleRepository.merge(role, updateRoleDto);
    if (updateRoleDto.permissionIds) {
      newRole.permissions = await this.permissionRep.find({
        where: { id: In(updateRoleDto.permissionIds) },
      });
    }
    await this.roleRepository.save(newRole);
    await this.userService.refreshAllOnlineUserPermission();
    return;
  }

  // 分配角色给用户
  async assignRoleToUser(roleId: number, roleDto: AssignRoleToUserDto) {
    const { userIds } = roleDto; // 结构出userIds
    const role = await this.roleRepository.findOne({
      where: { id: roleId },
      relations: { users: true },
    }); // 查询角色
    if (!role) throw new BadRequestException('角色不存在');
    if (userIds.length === 0) throw new BadRequestException('用户id不能为空');
    // 查询用户
    const users = await this.userRepository.find({ where: { id: In(userIds) } });
    role.users = role.users.filter((item) => !userIds.includes(item.id)).concat(users);
    await this.roleRepository.save(role);
    return true;
  }

  // 获取角色列表：分页
  async getRoleList(queryDto: GetRoleDto) {
    const { roleName, status } = queryDto;
    const pageSize: number = Number(queryDto.pageSize) || 10;
    const pageNo: number = Number(queryDto.pageNo) || 1;
    const [list, total] = await this.roleRepository
      .createQueryBuilder('role')
      .andWhere(roleName ? 'role.roleName LIKE :roleName' : '1=1', { roleName: `%${roleName}%` })
      .andWhere(status !== undefined ? 'role.status = :status' : '1=1', { status })
      .skip((pageNo - 1) * pageSize)
      .take(pageSize)
      .getManyAndCount();

    return {
      list,
      total,
      pageNo,
      pageSize,
    };
  }

  // 查询角色详情
  async getRoleDetail(roleId: number) {
    const role = await this.roleRepository.findOne({
      where: { id: roleId },
      relations: ['permissions'],
    });
    if (!role) throw new BadRequestException('角色不存在');
    role.permissions = this.sharedService.handleTree(role.permissions);
    return role;
  }

  // 获取角色
  async getRole(number: number) {
    const role = await this.roleRepository
      .createQueryBuilder('role')
      .leftJoinAndSelect('role.permissions', 'permission')
      .where('role.id = :id', { id: number })
      .getOne();

    if (!role) throw new BadRequestException('角色不存在');
    const permissionIds = role.permissions.map((permission) => permission.id);

    delete role.permissions;

    return {
      ...role,
      permissionIds,
    };
  }

  // 切换角色
  async switchRole(req: any, roleCode: string) {
    const { user } = req;
    await this.userService.refreshUserInfo(user.userId);
    const userInfo = JSON.parse(await this.redisService.get(`USER_INFO:${user.userId}`));
    if (!userInfo) throw new CustomException(ErrorCode.ERR_11006);
    if (!userInfo.roles.find((item: any) => item.roleCode === roleCode)) {
      throw new CustomException(ErrorCode.ERR_11006);
    }
    const role = await this.roleRepository.findOne({ where: { roleCode }, select: ['status'] });
    if (!role || !role.status) {
      throw new CustomException(ErrorCode.ERR_11008);
    }
    userInfo.currentRole = userInfo.roles.find((item: any) => item.roleCode === roleCode);
    userInfo.permissionIds = await this.permissionService.getPermissionIdsByRoleCode(
      userInfo.currentRole.roleCode,
    );
    await this.redisService.set(`USER_INFO:${user.userId}`, JSON.stringify(userInfo));
    await this.userRepository.update({ id: user.userId }, { lastRoleCode: roleCode });
    return true;
  }

  // 切换角色状态
  async switchRoleStatus(roleId: number) {
    const role = await this.roleRepository
      .createQueryBuilder('role')
      .leftJoinAndSelect('role.users', 'user')
      .where('role.id = :id', { id: roleId })
      .getOne();
    if (!role) throw new BadRequestException('角色不存在');
    role.status = !role.status;
    for (const item of role.users) {
      if (item.lastRoleCode === role.roleCode) {
        await this.redisService.del(`USER_ACCESS_TOKEN:${item.id}`);
        await this.redisService.del(`USER_INFO:${item.id}`);
      }
    }
    // 保存角色
    await this.roleRepository.save(role);
    return;
  }

  /**
   * 获取角色的菜单
   * @param req
   */
  async getUserPermission(req: any) {
    // 根据角色获取菜单，如果用户没有菜单，则返回默认菜单
    const { user } = req;
    const userPermissions = await this.permissionRep
      .createQueryBuilder('permission')
      .leftJoin('permission.roles', 'role')
      .where('role.roleCode = :roleCode', { roleCode: user.currentRole.roleCode })
      .orderBy('permission.sort', 'DESC')
      .select([
        'permission.id',
        'permission.permissionName',
        'permission.permissionCode',
        'permission.type',
        'permission.parentId',
        'permission.path',
        'permission.redirect',
        'permission.icon',
        'permission.component',
        'permission.keepAlive',
        'permission.isShow',
        'permission.isBase',
        'permission.method',
        'permission.status',
        'permission.sort',
      ])
      .getMany();
    console.log('userPermissions', userPermissions);
    return this.sharedService.handleTree(userPermissions);
  }
}
